/*
 * Copyright 2004-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package susano.common.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A utility class for {@link Annotation}.
 *
 * @author tanaka.akira.2006
 * @version $Id: AnnotationUtil.java 337 2009-10-15 05:26:51Z tanaka.akira.2006 $
 */
public final class AnnotationUtil {

	protected static final Logger logger = Logger
			.getLogger(AnnotationUtil.class.getName());

	private AnnotationUtil() {
	}

	/**
	 * 指定したアノテーションを持つフィールドを返します。
	 *
	 * @param obj
	 * @param annotation
	 * @return {@link Field}リスト
	 */
	public static List<Field> getFields(Object obj, final Class<?> annotation) {
		List<Field> fieldList = null;
		Field[] fs = obj.getClass().getFields();
		for (int i = 0; i < fs.length; i++) {
			Annotation[] annos = fs[i].getAnnotations();
			if (containsAnnotation(annos, annotation)) {
				if (fieldList == null) {
					fieldList = new ArrayList<Field>();
				}
				fieldList.add(fs[i]);
			}
		}
		return fieldList;
	}

	/**
	 * 指定したアノテーションを持つ最初のフィールドを返します。
	 *
	 * @param obj
	 * @param annotation
	 * @return 最初の{@link Field}
	 */
	public static Field getField(Object obj, final Class<?> annotation) {
		List<Field> fs = getFields(obj, annotation);
		if (fs != null) {
			return fs.get(0);
		}
		return null;
	}

	/**
	 * 指定したアノテーションを持つ最初のフィールドの値を返します。
	 *
	 * @param obj
	 * @param annotation
	 * @return 最初の{@link Field}の値
	 */
	public static Object getFieldVal(Object obj, final Class<?> annotation) {
		Field f = getField(obj, annotation);
		if (f != null) {
			try {
				return f.get(obj);
			} catch (IllegalArgumentException e) {
				logger.log(Level.WARNING, e.getMessage());
			} catch (IllegalAccessException e) {
				logger.log(Level.WARNING, e.getMessage());
			}
		}
		return null;
	}

	/**
	 * 指定したアノテーションを持つ最初のフィールドに値をセットします。
	 *
	 * @param obj
	 * @param value
	 *            セットする値
	 * @param annotation
	 */
	public static void setFieldVal(Object obj, Object value,
			final Class<?> annotation) {
		Field f = getField(obj, annotation);
		if (f != null) {
			try {
				f.set(obj, value);
			} catch (IllegalArgumentException e) {
				logger.log(Level.WARNING, e.getMessage());
			} catch (IllegalAccessException e) {
				logger.log(Level.WARNING, e.getMessage());
			}
		}
	}

	private static boolean containsAnnotation(final Annotation[] annos,
			final Class<?> annotation) {
		for (int i = 0; i < annos.length; i++) {
			if (annos[i].annotationType() == annotation) {
				return true;
			}
		}
		return false;
	}
}